home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 July / macformat-026.iso / mac / Shareware City / Developers / PopupCDEF-10b5 / Source / PopupDemo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-27  |  20.8 KB  |  707 lines  |  [TEXT/KAHL]

  1. /* See the file Distribution for distribution terms.
  2.     (c) Copyright 1994 Ari Halberstadt */
  3.  
  4. /* A simple program to test my Popup CDEF. A dialog containing various
  5.     types of popup controls is displayed. You can make selections from the
  6.     menus, and notice how the current item is marked with a check mark.
  7.     Click the "Quit" button to quit the program.
  8.     
  9.     A type-in popup menu is also demonstrated, and a functions that show
  10.     how type-in popup menus can be supported are provided. To make it
  11.     easier to find the relavent code, sections of code that are used
  12.     for the type-in popup menu are bracketed with "TYPEIN_BEGIN" and
  13.     "TYPEIN_END".
  14.     
  15.     94/08/25 aih - custom item is set with SetMenuItemText so metacharacters
  16.                         aren't interpreted
  17.     94/07/20 aih - shows both my CDEF and the system 7.0 CDEF
  18.     94/07/07 aih - adapted for universal headers
  19.     94/03/14 aih - created by hacking Thread Library test application */
  20.  
  21. #include <stdio.h>
  22. #include <strings.h>
  23. #include <Desk.h>
  24. #include <Dialogs.h>
  25. #include <Events.h>
  26. #include <Fonts.h>
  27. #include <GestaltEqu.h>
  28. #include <LowMem.h>
  29. #include <Memory.h>
  30. #include <Menus.h>
  31. #include <QuickDraw.h>
  32. #include <OSEvents.h>
  33. #include <OSUtils.h>
  34. #include <Resources.h>
  35. #include <TextUtils.h>
  36. #include <ToolUtils.h>
  37. #include <Traps.h>
  38. #include <Windows.h>
  39. #include "PopupLib.h"
  40.  
  41. /*----------------------------------------------------------------------------*/
  42. /* global definitions and declarations */
  43. /*----------------------------------------------------------------------------*/
  44.  
  45. #define CDEF_ATTACH         (1)
  46.  
  47. /* It is much easier to debug an application than it is to debug
  48.     a code resource. So that the CDEF can be debugged from within
  49.     an application, we can attach the CDEF compiled as part of this
  50.     application to a popup menu control, replacing the 'CDEF'
  51.     resource for the control. If you define CDEF_ATTACH as 1, then
  52.     the CDEF will be "attached", so that it can be debugged within
  53.     this application. */
  54. #ifndef CDEF_ATTACH
  55.     #define CDEF_ATTACH         (0)
  56. #endif /* CDEF_ATTACH */
  57.  
  58. /*    Number of dialogs we create. */
  59. #define MAXDLG                    (3)
  60.  
  61. /* structure of a 'CNTL' resource */
  62. typedef struct {
  63.     Rect bounds;
  64.     short value;
  65.     Boolean visible;
  66.     Boolean fill;
  67.     short max;
  68.     short min;
  69.     short procID;
  70.     long refCon;
  71.     Str255 title;
  72. } ControlTemplate, *ControlTemplatePtr, **ControlTemplateHandle;
  73.  
  74. /* dialog items */
  75. enum {
  76.     rDialog = 128,
  77.     iQuit = 1,
  78.     iFontPopup,
  79.     iSizeTitle,
  80.     iSizeText,
  81.     iSizePopup,
  82.     iStylePopup,
  83.     iAlignPopup,
  84.     iLongTitlePopup,
  85.     iIconsPopup,
  86.     iRightAlignedPopup,
  87.     iWindowFontPopup,
  88.     iDisabledItemPopup,
  89.     iDisabledPopup,
  90.     iNoTitlePopup,
  91.     iColorPopup,
  92.     iToggleDisabledPopup,
  93.     iPromptText,
  94.     iLast
  95. };
  96.  
  97. /*----------------------------------------------------------------------------*/
  98. /* assertions */
  99. /*----------------------------------------------------------------------------*/
  100.  
  101. #ifndef NDEBUG
  102.     #define myassert(x) ((void) ((x) || assertfailed()))
  103. #else
  104.     #define myassert(x) ((void) 0)
  105. #endif
  106.  
  107. #define require(x)    myassert(x)
  108. #define check(x)        myassert(x)
  109. #define ensure(x)        myassert(x)
  110.  
  111. static int assertfailed(void)
  112. {
  113.     DebugStr((StringPtr) "\p An assertion failed.");
  114.     return(0);
  115. }
  116.  
  117. /*----------------------------------------------------------------------------*/
  118. /* standard Macintosh initializations */
  119. /*----------------------------------------------------------------------------*/
  120.  
  121. /* initialize application heap */
  122. static void HeapInit(long stack, short masters)
  123. {
  124.     SetApplLimit(LMGetApplLimit() - stack);
  125.     MaxApplZone();
  126.     while (masters-- > 0)
  127.         MoreMasters();
  128. }
  129.  
  130. /* initialize managers */
  131. static void ManagersInit(void)
  132. {
  133.     EventRecord event;
  134.     short i;
  135.     
  136.     /* standard initializations */
  137.     InitGraf((Ptr) &qd.thePort);
  138.     InitFonts();
  139.     InitWindows();
  140.     InitMenus();
  141.     TEInit();
  142.     InitDialogs(0);
  143.     FlushEvents(everyEvent, 0);
  144.     InitCursor();
  145.     
  146.     /* so first window will be frontmost */
  147.     for (i = 0; i < 4; i++)
  148.         EventAvail(everyEvent, &event);
  149. }
  150.  
  151. /*----------------------------------------------------------------------------*/
  152. /* gestalt utilities */
  153. /*----------------------------------------------------------------------------*/
  154.  
  155. /* return the version of the Macintosh system software */
  156. static short MacVersion(void)
  157. {
  158.     OSErr err;
  159.     long response;
  160.     
  161.     err = Gestalt(gestaltSystemVersion, &response);
  162.     return(! err ? LoWord(response) : 0);
  163. }
  164.  
  165. /*----------------------------------------------------------------------------*/
  166. /* event utilities */
  167. /*----------------------------------------------------------------------------*/
  168.  
  169. /* Functions for determining whether a trap is available. Based on
  170.     functions given in IM VI. */
  171.  
  172. /* return number of toolbox traps */
  173. static short TrapNumToolbox(void)
  174. {
  175.     short result = 0;
  176.     
  177.     if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  178.         result = 0x0200;
  179.     else
  180.         result = 0x0400;
  181.     return(result);
  182. }
  183.  
  184. /* return the type of the trap */
  185. static TrapType TrapTypeGet(short trap)
  186. {
  187.     return((trap & 0x0800) > 0 ? ToolTrap : OSTrap);
  188. }
  189.  
  190. /* true if the trap is available  */
  191. static Boolean TrapAvailable(short trap)
  192. {
  193.     TrapType type;
  194.     
  195.     type = TrapTypeGet(trap);
  196.     if (type == ToolTrap) {
  197.         trap &= 0x07FF;
  198.         if (trap >= TrapNumToolbox())
  199.             trap = _Unimplemented;
  200.     }
  201.     return(NGetTrapAddress(trap, type) != NGetTrapAddress(_Unimplemented, ToolTrap));
  202. }
  203.  
  204. /* true if the WaitNextEvent trap is available */
  205. static Boolean MacHasWNE(void)
  206. {
  207.     static Boolean initialized;
  208.     static Boolean wne;
  209.     
  210.     if (! initialized) {
  211.         /* do only once for efficiency */
  212.         wne = TrapAvailable(_WaitNextEvent);
  213.         initialized = true;
  214.     }
  215.     return(wne);
  216. }
  217.  
  218. /* Call GetNextEvent or WaitNextEvent, depending on which one is available.
  219.     The parameters to this function are identical to those to WaitNextEvent.
  220.     If GetNextEvent is called the extra parameters are ignored. */
  221. static Boolean EventGet(short mask, EventRecord *event,
  222.     unsigned long sleep, RgnHandle cursor)
  223. {
  224.     Boolean result = false;
  225.  
  226.     if (MacHasWNE())
  227.         result = WaitNextEvent(mask, event, sleep, cursor);
  228.     else {
  229.         SystemTask();
  230.         result = GetNextEvent(mask, event);
  231.     }
  232.     if (! result) {
  233.         /* make sure it's a null event, even if the system thinks otherwise, e.g.,
  234.             some desk accessory events (see comment in TransSkell event loop) */
  235.         event->what = nullEvent;
  236.     }
  237.     return(result);
  238. }
  239.  
  240. /*----------------------------------------------------------------------------*/
  241. /* dialog utilities */
  242. /*----------------------------------------------------------------------------*/
  243.  
  244. /* get the text of the dialog item */
  245. static void GetDialogText(DialogPtr dlg, short item, Str255 str)
  246. {
  247.     short type;
  248.     Handle hitem;
  249.     Rect box;
  250.  
  251.     GetDialogItem(dlg, item, &type, &hitem, &box);
  252.     GetDialogItemText(hitem, str);
  253. }
  254.  
  255. /* set the text of the dialog item */
  256. static void SetDialogText(DialogPtr dlg, short item, ConstStr255Param str)
  257. {
  258.     short type;
  259.     Handle hitem;
  260.     Rect box;
  261.  
  262.     GetDialogItem(dlg, item, &type, &hitem, &box);
  263.     SetDialogItemText(hitem, str);
  264. }
  265.  
  266. /* return the numeric value of the dialog item */
  267. static long GetDialogNumber(DialogPtr dlg, short item)
  268. {
  269.     long num;
  270.     Str255 str;
  271.     
  272.     GetDialogText(dlg, item, str);
  273.     StringToNum(str, &num);
  274.     return(num);
  275. }
  276.  
  277. /* set the text of the dialog item to the number */
  278. static void SetDialogNumber(DialogPtr dlg, short item, long num)
  279. {
  280.     Str255 str;
  281.  
  282.     NumToString(num, str);
  283.     SetDialogText(dlg, item, str);
  284. }
  285.  
  286. /* return the control handle for the item */
  287. static ControlHandle GetDialogControl(DialogPtr dlg, short item)
  288. {
  289.     short type;
  290.     Handle hitem;
  291.     Rect box;
  292.  
  293.     GetDialogItem(dlg, item, &type, &hitem, &box);
  294.     return((ControlHandle) hitem);
  295. }
  296.  
  297. /* return a handle to the popup control's menu */
  298. static MenuHandle GetControlMenu(ControlHandle ctl)
  299. {
  300.     return((**(PopupPrivateHandle) (**ctl).contrlData).mHandle);
  301. }
  302.  
  303. /*----------------------------------------------------------------------------*/
  304. /* menu utilities */
  305. /*----------------------------------------------------------------------------*/
  306.  
  307. /*    Given a font family id and true in 'outlined', OutlineFontSizes will
  308.     outline all items in a size menu that actually exist in that font. If
  309.     'outlined' is false, all items will be set to plain text, which is
  310.     useful if you don't have any font information. */
  311. static void OutlineFontSizes(MenuHandle menu, short family, Boolean outlined)
  312. {
  313.     short        nitems;    /* number of items in menu */
  314.     short        item;        /* current item number */
  315.     long        size;        /* size of current menu item */
  316.     Str255    name;        /* name of item */
  317.     Boolean    found;    /* flag that we've already found the menu item */
  318.  
  319.     found = false;
  320.     nitems = CountMItems(menu);
  321.     for (item = 1; item <= nitems; item++) {
  322.         GetMenuItemText(menu, item, name);
  323.         StringToNum(name, &size);
  324.         if (outlined && RealFont(family, size))
  325.             SetItemStyle(menu, item, outline);
  326.         else
  327.             SetItemStyle(menu, item, 0);
  328.     }
  329. }
  330.  
  331. /* TYPEIN_BEGIN */
  332. /* return item number with given title, or 0 if not found */
  333. static short FindMenuItem(MenuHandle menu, ConstStr255Param ptitle)
  334. {
  335.     short item;        /* index to menu items */
  336.     short nitems;    /* number of items in menu */
  337.     Str255 name;    /* name of current item */
  338.     
  339.     nitems = CountMItems(menu);
  340.     for (item = 1; item <= nitems; item++) {
  341.         GetMenuItemText(menu, item, name);
  342.         if (EqualString(ptitle, name, false, true))
  343.             break;
  344.     }
  345.     return(item <= nitems ? item : 0);
  346. }
  347. /* TYPEIN_END */
  348.  
  349. /* TYPEIN_BEGIN */
  350. /*    AdjustTypeInPopupMenu adjusts a type-in popup menu. The 'dlg' parameter
  351.     is a pointer to the dialog containing the type-in popup meun. The
  352.     'popupItem' parameter is the item number of a type-in popup control. The
  353.     'textItem' parameter is the item number of the type-in editable text field.
  354.     The 'insertedCustomValue' parameter should initially be false; subsequently,
  355.     it must contain the value returned by the previous call to
  356.     AdjustTypeInPopupMenu.
  357.     
  358.     You should call AdjustTypeInPopupMenu whenever there's a click in the
  359.     popup menu control, but before TrackControl (or DialogSelect) is called
  360.     to handle the click. If the user entered a value into the text field that
  361.     is not in the popup menu, then the user's entry is inserted as the
  362.     first item in the popup menu and a dashed line is inserted to separate
  363.     the user's entry from the predefined values in the menu. When the user
  364.     chooses a menu item or enters a value into the text field that is one of
  365.     the predefined values in the menu, then the items inserted into the menu
  366.     are deleted. The 'insertedCustomValue' flag is used to determine if a
  367.     user's entry was inserted into the menu. */
  368. static Boolean AdjustTypeInPopupMenu(DialogPtr dlg,
  369.     short popupItem, short textItem,
  370.     Boolean insertedCustomValue)
  371. {
  372.     ControlHandle ctl;    /* handle to size popup control */
  373.     MenuHandle menu;        /* handle to popup menu's handle */
  374.     short item;                /* index to item in menu */
  375.     short nitems;            /* number of items in size menu */
  376.     Str255 text;            /* string in text item */
  377.     
  378.     /* adjust user's choice */
  379.     GetDialogText(dlg, textItem, text);
  380.     ctl = GetDialogControl(dlg, popupItem);
  381.     menu = GetControlMenu(ctl);
  382.     item = FindMenuItem(menu, text);
  383.     if (item == 0 && *text) {
  384.  
  385.         /* user entered a size not found in the menu, so add the user's
  386.             choice as the first item in the menu (IM-VI, p2-37) */
  387.         if (! insertedCustomValue) {
  388.             InsertMenuItem(menu, (StringPtr) "\p(-", 0);
  389.             InsertMenuItem(menu, (StringPtr) "\pnot empty", 0);
  390.             SetMenuItemText(menu, 1, text);
  391.             for (nitems = CountMItems(menu); nitems > 0; nitems--)
  392.                 SetItemMark(menu, nitems, noMark);
  393.             SetItemMark(menu, 1, checkMark);
  394.             SetControlMaximum(ctl, GetControlMaximum(ctl) + 2);
  395.             insertedCustomValue = true;
  396.         }
  397.         SetMenuItemText(menu, 1, text);
  398.         SetControlValue(ctl, 1);
  399.     }
  400.     else if ((item > 2 || *text == 0) && insertedCustomValue) {
  401.  
  402.         /* remove user's choice, since selected item is in menu
  403.             (or selected item is empty) */
  404.         insertedCustomValue = false;
  405.         SetControlValue(ctl, 1);
  406.         DeleteMenuItem(menu, 1);
  407.         DeleteMenuItem(menu, 1);
  408.         SetControlMaximum(ctl, GetControlMaximum(ctl) - 2);
  409.         SetControlValue(ctl, item - 2);
  410.     }
  411.     else
  412.         SetControlValue(ctl, item);
  413.  
  414.     return(insertedCustomValue);
  415. }
  416. /* TYPEIN_END */
  417.  
  418. /*----------------------------------------------------------------------------*/
  419. /* the event loop */
  420. /*----------------------------------------------------------------------------*/
  421.  
  422. /* create the dialog and run the program */
  423. static void EventLoop(DialogPtr *dialogs)
  424. {
  425.     Boolean sizeHasCustomValue;/* true if inserted a value into type-in menu */
  426.     EventRecord event;            /* event record for getting next event */
  427.     Boolean quit;                    /* true if time to quit application */
  428.     Rect dragRect;                    /* rectangle within which to drag windows */
  429.     Str255 str;                        /* utility string */
  430.     DialogPtr dlgHit;                /* for handling dialog events */
  431.     short itemHit;                    /* for handling dialog events */
  432.     Point where;                    /* for handling dialog events */
  433.     short font;                        /* for getting font */
  434.     short i;                            /* index to dialogs */
  435.     
  436.     sizeHasCustomValue = false;
  437.     quit = false;    
  438.     while (! quit) {
  439.     
  440.         /* Set the dialog's font and font size so we can see the effect of the
  441.             useWFont variation code. We need to do this once every time through
  442.             the event loop since (in system 6.0) DialogSelect resets the font
  443.             to the system font. */
  444.         for (i = 0; dialogs[i]; i++) {
  445.             SetPort(dialogs[i]);
  446.             TextFont(geneva);
  447.             TextSize(9);
  448.         }
  449.     
  450.         /* handle the next event; this is a pretty simple event loop */
  451.         SetCursor(&qd.arrow);
  452.         (void) EventGet(everyEvent, &event, GetCaretTime(), NULL);
  453.         switch (event.what) {
  454.         case mouseDown:
  455.             switch (FindWindow(event.where, &dlgHit)) {
  456.             case inDrag:
  457.                 /* handle a click in the drag bar */
  458.                 SelectWindow(dlgHit);
  459.                 dragRect = (**GetGrayRgn()).rgnBBox;
  460.                 DragWindow(dlgHit, event.where, &dragRect);
  461.                 break;
  462.             case inContent:
  463.                 SelectWindow(dlgHit);
  464.                 where = event.where;
  465.                 SetPort(dlgHit);
  466.                 GlobalToLocal(&where);
  467.                 /* TYPEIN_BEGIN */
  468.                 /* check if user is clicking in size type-in popup menu */
  469.                 for (i = 0; dialogs[i]; i++) {
  470.                     if (dlgHit == dialogs[i]) {
  471.                         if (FindDialogItem(dlgHit, where) + 1 == iSizePopup) {
  472.         
  473.                             /* adjust the size popup menu before it's pulled down */
  474.                             sizeHasCustomValue = AdjustTypeInPopupMenu(dlgHit,
  475.                                                                 iSizePopup, iSizeText,
  476.                                                                 sizeHasCustomValue);
  477.  
  478.                             /* outline font sizes available in the selected font */
  479.                             GetFNum(str, &font);
  480.                             GetMenuItemText(GetControlMenu(GetDialogControl(dlgHit, iFontPopup)),
  481.                                 GetControlValue(GetDialogControl(dlgHit, iFontPopup)), str);
  482.                             OutlineFontSizes(GetControlMenu(GetDialogControl(dlgHit, iSizePopup)),
  483.                                 font, true);
  484.                         }
  485.                         break;
  486.                     }
  487.                 }
  488.                 /* TYPEIN_END */
  489.                 break;
  490.             }
  491.             break;
  492.         }
  493.         
  494.         /* handle dialog events */
  495.         if (IsDialogEvent(&event) && DialogSelect(&event, &dlgHit, &itemHit)) {
  496.             
  497.             /* handle a click in one of the dialog's buttons */
  498.             switch (itemHit) {
  499.             case iSizePopup:
  500.                 /* TYPEIN_BEGIN */
  501.                 /* Set the value displayed in the text field to the value
  502.                     chosen from the size popup menu and select the text in
  503.                     the size edit field. */
  504.                 GetMenuItemText(GetControlMenu(GetDialogControl(dlgHit, iSizePopup)),
  505.                     GetControlValue(GetDialogControl(dlgHit, iSizePopup)), str);
  506.                 SetDialogText(dlgHit, iSizeText, str);
  507.                 SelectDialogItemText(dlgHit, iSizeText, 0, 32767);
  508.                 /* TYPEIN_END */
  509.                 break;
  510.             case iToggleDisabledPopup:
  511.                 SetControlValue(GetDialogControl(dlgHit, iToggleDisabledPopup),
  512.                     ! GetControlValue(GetDialogControl(dlgHit, iToggleDisabledPopup)));
  513.                 if (GetControlValue(GetDialogControl(dlgHit, iToggleDisabledPopup))) {
  514.                     SetControlTitle(GetDialogControl(dlgHit, iDisabledPopup),
  515.                         (StringPtr) "\pEnabled:");
  516.                     HiliteControl(GetDialogControl(dlgHit, iDisabledPopup), 1);
  517.                 }
  518.                 else {
  519.                     SetControlTitle(GetDialogControl(dlgHit, iDisabledPopup),
  520.                         (StringPtr) "\pDisabled:");
  521.                     HiliteControl(GetDialogControl(dlgHit, iDisabledPopup), 255);
  522.                 }
  523.                 break;
  524.             case iQuit:
  525.                 quit = true;
  526.                 break;
  527.             }
  528.         }
  529.         
  530.         /* TYPEIN_BEGIN */
  531.         /* Remove the custom value from the menu, so we don't interfere
  532.             with the size popup menu in the other dialog (where the other
  533.             dialog is the dialog that uses either my popup CDEF or the
  534.             system popup CDEF). We only do this because we're sharing
  535.             the same menu handle with two control items, and because the
  536.             menu handle must contain different data in each control. */
  537.         if (sizeHasCustomValue) {
  538.             ControlHandle ctl = GetDialogControl(dlgHit, iSizePopup);
  539.             MenuHandle menu = GetControlMenu(ctl);
  540.             sizeHasCustomValue = false;
  541.             SetControlValue(ctl, 1);
  542.             DeleteMenuItem(menu, 1);
  543.             DeleteMenuItem(menu, 1);
  544.             SetControlMaximum(ctl, GetControlMaximum(ctl) - 2);
  545.             SetControlValue(ctl, 1);
  546.         }
  547.         /* TYPEIN_END */
  548.     }
  549. }
  550.  
  551. /*----------------------------------------------------------------------------*/
  552. /* initialization */
  553. /*----------------------------------------------------------------------------*/
  554.  
  555. /* abort on error */
  556. static void fatal(Boolean exit, ConstStr255Param msg)
  557. {
  558.     if (exit) {
  559.         DebugStr(msg);
  560.         ExitToShell();
  561.     }
  562. }
  563.  
  564. /* create a dialog using the specified procID */
  565. static DialogPtr CreateDialogUsingProcID(short procID, short slot,
  566.     const char *prompt, ConstStr255Param title)
  567. {
  568.     DialogPtr dlg;                    /* the dialog */
  569.     Point position;                /* position of dialog */
  570.     Str255 promptFormat;            /* for formatting prompt string */
  571.     char promptText[256];        /* for setting prompt string */
  572.     short i;                            /* index to 'CNTL' resources */
  573.     short ncntl;                    /* number of 'CNTL' resources */
  574.     ControlTemplateHandle cntl;/* handle to 'CNTL' resource */
  575.  
  576.     /* change the 'CNTL' resources to use the specified procID */
  577.     ncntl = Count1Resources('CNTL');
  578.     for (i = 1; i <= ncntl; i++) {
  579.         cntl = (ControlTemplateHandle) Get1IndResource('CNTL', i);
  580.         if (cntl && *cntl) {
  581.             HNoPurge((Handle) cntl);
  582.             if (((**cntl).procID & 0xFFF0) != procID)
  583.                 (**cntl).procID = ((**cntl).procID & 0x000F) + procID;
  584.         }
  585.     }
  586.  
  587.     /* create the dialog */
  588.     dlg = GetNewDialog(rDialog, NULL, (WindowPtr) -1);
  589.     fatal(! dlg, "\p nil dialog pointer");
  590.  
  591.     /* release all the 'CNTL' resources (so they'll be reloaded from
  592.         disk the next time we're called) */
  593.     for (i = 1; i <= ncntl; i++) {
  594.         cntl = (ControlTemplateHandle) Get1IndResource('CNTL', i);
  595.         if (cntl && *cntl)
  596.             ReleaseResource((Handle) cntl);
  597.     }
  598.  
  599.     /* select the type-in menu's text field */
  600.     SelectDialogItemText(dlg, iSizeText, 0, 32767);
  601.     
  602.     /* disable a popup menu control so we can see what a disabled popup
  603.         menu control looks like */
  604.     HiliteControl(GetDialogControl(dlg, iDisabledPopup), 255);
  605.     
  606.     /* set prompt string */
  607.     GetDialogText(dlg, iPromptText, promptFormat);
  608.     sprintf(promptText, p2cstr(promptFormat), prompt);
  609.     SetDialogText(dlg, iPromptText, c2pstr(promptText));
  610.     SetWTitle(dlg, title);
  611.  
  612.     /* position dialog */
  613.     position.h = qd.screenBits.bounds.left + GetMBarHeight() + 4 + 10 * slot;
  614.     position.v = qd.screenBits.bounds.top + GetMBarHeight() + 4 + 20 * (slot + 1);
  615.     MoveWindow(dlg, position.h, position.v, false);
  616.  
  617.     return(dlg);
  618. }
  619.  
  620. /* create the dialog using the system 7 CDEF */
  621. static DialogPtr CreateDialogUsingSystemCDEF(void)
  622. {
  623.     DialogPtr dlg;
  624.     
  625.     dlg = CreateDialogUsingProcID(popupMenuProc, 0,
  626.         "the system", (StringPtr) "\pSystem Popup CDEF");
  627.     return(dlg);
  628. }
  629.  
  630. /* create the dialog using my popup CDEF */
  631. static DialogPtr CreateDialogUsingMyCDEF(void)
  632. {
  633.     DialogPtr dlg;                    /* the dialog */
  634.     short i;                            /* index to popup menu items */
  635.     const short popups[] = {    /* all of the popup menu items in the dialog */
  636.         iFontPopup,
  637.         iSizePopup,
  638.         iStylePopup,
  639.         iAlignPopup,
  640.         iLongTitlePopup,
  641.         iIconsPopup,
  642.         iRightAlignedPopup,
  643.         iWindowFontPopup,
  644.         iDisabledItemPopup,
  645.         iDisabledPopup,
  646.         iNoTitlePopup,
  647.         iColorPopup,
  648.         0,
  649.     };
  650.     
  651.     dlg = CreateDialogUsingProcID(kPopupProcID, 1, "my", (StringPtr) "\pMy Popup CDEF");
  652.  
  653.     #if CDEF_ATTACH
  654.         /* It is much easier to debug an application than it is to debug
  655.             a code resource. So that the CDEF can be debugged from within
  656.             an application, we attach the CDEF compiled as part of this
  657.             application to a popup menu control, replacing the 'CDEF'
  658.             resource for the control. */
  659.         for (i = 0; popups[i]; i++)
  660.             PopupCDEFAttach(GetDialogControl(dlg, popups[i]));
  661.     #endif /* CDEF_ATTACH */
  662.  
  663.     return(dlg);
  664. }
  665.  
  666. /* create the dialogs and run the event loop */
  667. static void Run(void)
  668. {
  669.     DialogPtr dialogs[MAXDLG];    /* array of dialogs we created */
  670.     DialogPtr dlgSysCDEF;        /* dialog using system popup CDEF */
  671.     DialogPtr dlgMyCDEF;            /* dialog using my popup CDEF */
  672.     short ndialogs;                /* number of dialogs we created */
  673.     short i;                            /* index to array of dialogs */
  674.     
  675.     /* initialize dialogs */
  676.     ndialogs = 0;
  677.     dlgSysCDEF = dlgMyCDEF = NULL;
  678.     for (i = 0; i < MAXDLG; i++)
  679.         dialogs[i] = NULL;
  680.     
  681.     /* create a dialog using the system popup CDEF */
  682.     if (MacVersion() >= 0x0700)
  683.         dlgSysCDEF = dialogs[ndialogs++] = CreateDialogUsingSystemCDEF();
  684.     
  685.     /* create a dialog using my popup CDEF */
  686.     dlgMyCDEF = dialogs[ndialogs++] = CreateDialogUsingMyCDEF();
  687.  
  688.     /* show the dialogs */
  689.     SelectWindow(dlgMyCDEF);
  690.     ShowWindow(dlgMyCDEF);
  691.     if (dlgSysCDEF)
  692.         ShowWindow(dlgSysCDEF);
  693.         
  694.     /* run the event loop */
  695.     EventLoop(dialogs);
  696.     
  697.     /* we could detach the popup menus (with PopupCDEFDetach) and dispose of the
  698.         dialogs, but since we're quitting the application there's no need to */
  699. }
  700.  
  701. void main(void)
  702. {
  703.     HeapInit(0, 4);
  704.     ManagersInit();
  705.     Run();
  706. }
  707.